#include "CEnemy.h"
//#include "CHomingWeapon.h"
//#include "CBounceWeapon.h"
//#include "CLaserWeapon.h"
#include "CWave.h"
#include "CGameApp.h"

extern float VIEW_WIDTH;
extern float VIEW_HEIGHT;

extern bool IsItemUpdating(CSpecialItem* item);

//this function should be called by listname.remove_if() only
bool ActionDone( CAction* action )
{
	//updateaction returns false if it didn't update. the function doesn't update if it's done
	if( action->UpdateAction() == false )
	{ 
		delete action;
		return true;
	}
	else
	{ return false; }
	//return (!action->UpdateAction());
}

CAction::CAction( CEnemy* owner )
:Owner(NULL),
Action(NULL),
ActionChange(0),
ActionTime(0),
ActionTimer(0),
ActionAlive(false)
{
	if( owner == NULL ) { cout << "enemy not connected to action" << endl; }
	Owner = owner;
}

CAction::~CAction()
{
	Owner = NULL;
}

void CAction::PerformAction( float& action, float change, float time )
{
	ActionAlive = true;
	Action = &action;
	ActionChange = change;
	ActionTime = time;
	ActionTimer = time;
}

bool CAction::UpdateAction()
{
	if( Owner->GetAlive() == false ) { return true; }
	//lower the timer
	ActionTimer -= Owner->pParent->DeltaTime;

	//if the timer is less than zero the action no longer needs updating
	if( ActionTimer <= 0.0f )
	{
		ActionAlive = false;
		return false; //to let the caller know the action's completed
	}	
	//actiontimer/actiontime = amount to move action by/total amount to move action by
	//performaction( ypos, +5, 2sec )
	//if( Owner->GetAlive() )
	//{
		(*Action) += ActionChange * Owner->pParent->DeltaTime / ActionTime;
	//}
	return true;

}




CEnemy::CEnemy()
:CEntity(),
PrimaryWeapon(NULL),
TimeAlive(0.0f),
TimeUntilAlive(0.0f),
Waiting(false),
ParentWave(NULL),
//Command( NULL ),
Commands(0),
//Items(0),
state(0)
//inloop(false)
//Action(NULL),
//ActionChange(0),
//ActionTime(0),
//ActionTimer(0),
//ActionAlive(false)
{
	//Action = ActionTimer;
	PrimaryWeapon = new CWeapon(0,0);//(5,1);//CLaserWeapon(1,2);//CBounceWeapon(3,2);//CHomingWeapon(5,1);//BounceWeapon( 10 , 2);
	PrimaryWeapon->Attach( this );
	SetType( "CEnemy" );
	PrimaryWeapon->RateOfFire = 1.8f;
	//Command = new CAction( this );
	//PrimaryWeapon->SpreadAngle = 20.0f;
}

CEnemy::~CEnemy()
{
	if( PrimaryWeapon ) { delete PrimaryWeapon; }
	ParentWave = NULL;
	//delete Command;
	list<CAction*>::iterator i;
	for( i = Commands.begin(); i != Commands.end(); i++ )
	{
		delete (*i);
		//Commands.erase( i );
		//i--;
	}
	Commands.clear();
	
	//list< CSpecialItem* >::iterator j;
	//for( j = Items.begin(); j != Items.end(); j++ )
	//{
	//	delete (*j);
	//	
	//}
	//Items.clear();
}

void CEnemy::Render()
{
	CEntity::Render();
	PrimaryWeapon->Render(); //renders the bullets

	//list< CSpecialItem* >::iterator i;
	//for( i = Items.begin(); i != Items.end(); i++ )
	//{
	//	if( (*i) == NULL ) { continue; }
	//		
	//	(*i)->Render();	
	//}
}

void CEnemy::Update()
{
	if( GetAlive() == false && Waiting == true )//TimeUntilAlive >= 0 )
	{
		TimeUntilAlive -= pParent->DeltaTime;//	decrease timeuntil alive
		if( TimeUntilAlive <= 0 )
		{
			SetWaiting( false );
			SetAlive( true );
			SetTimeAlive( 0 );// = 0;
		}
	}
	if( GetAlive() == true )
	{
		//TimeAlive += pParent->DeltaTime;
		//MovePosY( pParent->DeltaTime * GetSpeed() * GetVelY() ); 
		//MovePosX( pParent->DeltaTime * GetSpeed() * GetVelX() );
		if( GetPosY() < -pParent->WorldEdge || GetPosY() > pParent->WorldEdge
			|| GetPosX() < -pParent->WorldEdge || GetPosX() > pParent->WorldEdge )
		{ Kill(); }
			
		TimeAlive += pParent->DeltaTime;
		SetOldPos( GetPosX(), GetPosY() );
		if( TimeAlive >= 1.0f )// && Enemy[i]->TimeAlive < 20.1f )
		{
				//state and inloop need to be a member variable that each enemy has
				//static int state = 0;
				static bool inloop = false;//true;
				if( Commands.empty() )
				{
					state += 1;
					state %= 4;//state % 4;
					inloop = true;
				}
				if( inloop == true )
				{
					switch( state )
					{
					//move right
					case 0:
						PerformAction( Pos.y , 0, 1.0f );
						inloop = false;
						break;
						//move down
					case 1:
						PerformAction( Pos.x , 4, 2 );
						inloop = false;
						break;
						//move left
					case 2:
						PerformAction( Pos.y , 0, 1.0f );
						inloop = false;
						break;
						//move down
					case 3:
						PerformAction( Pos.x , -4, 2 );
						inloop = false;
						break;
					default:
						break;
					}
				}//endif
		}
		//	) { Kill(); }
		//if( GetPosX() < VIEW_WIDTH * -0.5f || GetPosX() > VIEW_WIDTH * 0.5f ) { Kill(); }
		//if( TimeAlive >= 1.0f )
		//{
		//	SetFaceAngle( pParent->Player->GetPosX(), pParent->Player->GetPosY() );
		//	//RotateFaceAngleBy( pParent->DeltaTime*GetRotateSpeed() * 360 );
		//}
		//else
		//{
		//	RotateFaceAngleBy( -pParent->DeltaTime*GetRotateSpeed() * 360 );
		//	//SetFaceAngle( pParent->Player->GetPosX(), pParent->Player->GetPosY() );
		//	SetOldPos( GetPosX(), GetPosY() );
		//	//cout << GetVelX() << " " << GetVelY() << endl;
		//	MovePosY( pParent->DeltaTime*GetSpeed()*GetVelY() );
		//	MovePosX( pParent->DeltaTime*GetSpeed()*GetVelX() );
		//	FireBullet();
		//}
	}

	//if( GetAlive() == false && GetEAlive() == false && Waiting == false )
	//{

	//}

	//}
	//		increase timealive
	//		//adjust flight path depending on timealive
	//		if timealive is greater than 3 seconds
	//			adjust velocity
	//		else if timealive is greater than 2 seconds
	//			adjust velocity
	//	endif alive

	//SetFaceAngle( pParent->Player->GetPosX(), pParent->Player->GetPosY() );
	UpdateCommands();
	//
//	UpdateAttachedItems();
	CEntity::Update();
	PrimaryWeapon->Update();
}

void CEnemy::Load()
{
	if( pParent == NULL ) { cout << "CEnemy load failed, no game attached" << endl; return; }
	SetAlive(true);
	SetHealth( 3 );
	SetDamage( 1.0f );
	SetFaceAngle( 90.0f );
	SetPos( -9.0f + 2, 7.0f );
	SetOldPos( GetPosX(), GetOldPosY() );
	//SetVel( 0.0f, 1.0f );
	SetSpeed( 6.0f );
	SetRotateSpeed( 1.0f );//0.2f * (0.2f) );
	SetSize( 1.8f );
	SetCollisionSize( 1.7f );
	SetTexture( pParent->EnemyTexture.texID );
	SetDamageTexture( pParent->EnemyDamageTexture.texID );
	SetExplosionTexture( pParent->EnemyExplosionTexture );
	SetETextureSize( 4 );
	PrimaryWeapon->SetGame( pParent );
	PrimaryWeapon->Load();

}

void CEnemy::FireBullet()
{
	PrimaryWeapon->FireBullet();
}

void CEnemy::EquipPrimary( CWeapon* weapon )
{
	if( weapon == NULL ) { return; }
	if( PrimaryWeapon )
	{
		PrimaryWeapon->Kill();
		delete PrimaryWeapon;
		weapon->Attach( this );
		weapon->Load();
		PrimaryWeapon = weapon;
	}

}

void CEnemy::UpdateCommands()
{
	//Command->UpdateAction();
	Commands.remove_if(ActionDone);
	//list<CAction*>::iterator i = Commands.begin();
	////while( i != Commands.end() )
	//for( i = Commands.begin(); i != Commands.end(); i++ )
	//{
	//	if( (*i)->UpdateAction() == false )
	//	{
	//		delete (*i);
	//		Commands.erase( i );
	//		break;
	//		//continue;
	//		//if( Commands.begin() != i )
	//		//{ i--; }
	//	}
	//}
}

void CEnemy::PerformAction( float& action, float change, float time )
{
	//if( (int)Commands.size() > 3 ) { return; }
	CAction* command = new CAction( this );
	command->ActionAlive = true;
	command->Action = &action;
	command->ActionChange = change;
	command->ActionTime = time;
	command->ActionTimer = time;
	Commands.push_back( command );
}
/*
bool CEnemy::UpdateAction()
{

	//lower the timer
	ActionTimer -= pParent->DeltaTime;

	//if the timer is less than zero the action no longer needs updating
	if( ActionTimer <= 0.0f )
	{
		ActionAlive = false;
		return false; //to let the caller know the action's completed
	}
	//cout << "actionalive true" << endl;	
	//actiontimer/actiontime = amount to move action by/total amount to move action by
	//performaction( ypos, +5, 2sec )
	(*Action) += ActionChange * pParent->DeltaTime / ActionTime;
	return true;

}
*/

void CEnemy::TakeDamage( float damage)
{
	SetHealth( GetHealth() - damage );
	StartDamageAnimation();
	if( GetHealth() <= 0 )
	{
		SetAlive( false );
		StartExplosion();
		PrimaryWeapon->Kill();
//	DropItem();
//	RemoveAllItems();
		if( GetParentWave() == NULL ) { return; }
	//find a way to make performAction work with int so the enemies remaining variable will go down after the explosion happens
		ParentWave->EnemiesRemaining -= 1;
		pParent->Player[0]->FriendLevel += 1;  //if i make friendlevel a float, i can use % to turn it into an int to require more friends per boost
		//CSpecialItem* speedplus = 
		if( pParent->Player[0]->Items.empty() == false )
		{
			list< CSpecialItem* >::iterator i = pParent->Player[0]->Items.begin();
			delete (*i);
			pParent->Player[0]->Items.pop_front();
			//pParent->Player[0]->Items
		}
	//	//release ghost
	//	//increase player friend count
	//	//increase player speed and jump height
	}
}

void CEnemy::Kill()
{
	SetAlive( false );
	StartExplosion();
	PrimaryWeapon->Kill();
//	DropItem();
//	RemoveAllItems();
	if( GetParentWave() == NULL ) { return; }
	//find a way to make performAction work with int so the enemies remaining variable will go down after the explosion happens
	ParentWave->EnemiesRemaining -= 1;

//	//release ghost
	CSpecialItem* Ghost = new CSpecialItem();
	Ghost->SetGame( pParent );
	Ghost->Load();
	Ghost->SetAlive( true );
	pParent->Player[0]->AttachItem( Ghost );
	//attach ghost to player
	//decrease friend count
	pParent->Player[0]->FriendLevel -= 1;
	//slow player
	//decrease player jump height

}


void CEnemy::AttachItem( CSpecialItem* itemtoadd )
{
	//cout << "inAttachItem and pointer is " << itemtoadd << endl;
	if( itemtoadd )
	{
		itemtoadd->SetIsItemAttached( true );
		itemtoadd->SetUpdating(true);
		itemtoadd->AttachToHost( this );
		Items.push_back( itemtoadd );
	}
	//cout << "made it through players attachitem" << endl;
}

void CEnemy::UpdateAttachedItems()
{
	list< CSpecialItem* >::iterator i;
	for( i = Items.begin(); i != Items.end(); i++ )
	{
		if( (*i) == NULL ) { continue; }
		if( (*i)->GetIsItemAttached() )
		{
			(*i)->UpdateAttached();
		}
	}
	Items.remove_if( IsItemUpdating );
}

void CEnemy::RemoveItem( CSpecialItem* itemtoremove )
{
	if( itemtoremove )
	{
		delete itemtoremove;
		Items.remove( itemtoremove );
	}
}

void CEnemy::RemoveAllItems()
{
	list< CSpecialItem* >::iterator i;
	for( i = Items.begin(); i != Items.end(); i++ )
	{
		delete (*i);
		
	}
	Items.clear();

}

void CEnemy::DropItem()
{
	if( rand() % 1 > 0 ) { return; } //10% chance of drop

	CSpecialItem* speed = new CSpecialItem();
	speed->SetGame( pParent );
	speed->Load();
	speed->SetPos( GetPosX(), GetPosY() );
	speed->SetVel( 0, -1);
	speed->SetTimeUntilAlive(0);
	speed->SetOldPos( speed->GetPosX(), speed->GetPosY()-0.01f );
	pParent->AddItem( speed );
}


